package yunjiao.javatutorials.guava.concurrent;

import com.google.common.util.concurrent.Monitor;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 有界缓存池
 *
 * @author yangyunjiao
 */
public class BoundedObjectPool<T> {
    private final Monitor monitor = new Monitor();
    private final Queue<T> available = new LinkedList<>();
    private final Set<T> inUse = new HashSet<>();
    private final int maxSize;
    private final long maxWaitTime;

    // 复杂条件：有可用对象 或 可以创建新对象
    private final Monitor.Guard canAcquire = new Monitor.Guard(monitor) {
        @Override
        public boolean isSatisfied() {
            return !available.isEmpty() || inUse.size() < maxSize;
        }
    };

    // 条件：有可用对象
    private final Monitor.Guard hasAvailable = new Monitor.Guard(monitor) {
        @Override
        public boolean isSatisfied() {
            return !available.isEmpty();
        }
    };

    private final ObjectFactory<T> factory;

    public interface ObjectFactory<T> {
        T create();
        boolean validate(T obj);
        void destroy(T obj);
    }

    public BoundedObjectPool(int maxSize, long maxWaitTime, ObjectFactory<T> factory) {
        this.maxSize = maxSize;
        this.maxWaitTime = maxWaitTime;
        this.factory = factory;
    }

    public T acquire() throws InterruptedException {
        if (!monitor.enterWhen(canAcquire, maxWaitTime, TimeUnit.MILLISECONDS)) {
            throw new InterruptedException("Timeout while waiting to acquire object");
        }
        try {
            if (!available.isEmpty()) {
                // 使用现有对象
                T obj = available.poll();
                if (factory.validate(obj)) {
                    inUse.add(obj);
                    return obj;
                } else {
                    // 对象无效，销毁并创建新的
                    factory.destroy(obj);
                }
            }

            // 创建新对象
            T obj = factory.create();
            inUse.add(obj);
            return obj;
        } finally {
            monitor.leave();
        }
    }

    public void release(T obj) {
        monitor.enter();
        try {
            if (inUse.remove(obj)) {
                if (factory.validate(obj)) {
                    available.offer(obj);
                } else {
                    factory.destroy(obj);
                }
            }
        } finally {
            monitor.leave();
        }
    }

    public Optional<T> tryAcquire() {
        if (monitor.tryEnterIf(canAcquire)) {
            try {
                if (!available.isEmpty()) {
                    T obj = available.poll();
                    if (factory.validate(obj)) {
                        inUse.add(obj);
                        return Optional.of(obj);
                    }
                }

                if (inUse.size() < maxSize) {
                    T obj = factory.create();
                    inUse.add(obj);
                    return Optional.of(obj);
                }
                return Optional.empty();
            } finally {
                monitor.leave();
            }
        }
        return Optional.empty();
    }

    // 统计信息
    public PoolStats getStats() {
        monitor.enter();
        try {
            return new PoolStats(available.size(), inUse.size(), maxSize);
        } finally {
            monitor.leave();
        }
    }

    public static class PoolStats {
        public final int available;
        public final int inUse;
        public final int maxSize;

        public PoolStats(int available, int inUse, int maxSize) {
            this.available = available;
            this.inUse = inUse;
            this.maxSize = maxSize;
        }
    }
}
